package com.yk.common.core.utils;

import cn.hutool.core.date.DateUtil;
import org.apache.commons.compress.utils.Lists;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneOffset;
import java.util.*;

/**
 * 日期时间工具类
 *
 * @author lmx
 * @date 2023/11/29 16:46
 */
public class DateUtils {

    public static final String DATE_MOUTH_FORMAT = "MM-dd";
    public static final String DATE_HOURS_FORMAT = "HH";
    public static final String DATE_STR_FORMAT = "MMddHHmmss";
    public static final String DATE_FORMAT = "YYYY-MM-dd HH:mm:ss";
    public static final String SIMPLE_FORMAT = "YYYY-MM-dd";
    public static final String MONTH_DAY = "MM.dd";

    /**
     * 获得本周一与参数日期相差的天数
     *
     * @param date 当前日期
     * @return 相差天数
     */
    public static int getMondayPlus(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
        //由于Calendar提供的都是以星期日作为周一的开始时间
        if (dayOfWeek == 1) {
            return -6;
        } else {
            return 2 - dayOfWeek;
        }
    }

    /**
     * 获取每天的开始时间 00:00:00:00
     *
     * @param date 时间
     * @return 本日开始时间
     */
    public static Date getDayStartTime(Date date) {
        Calendar dateStart = Calendar.getInstance();
        dateStart.setTime(date);
        dateStart.set(Calendar.HOUR_OF_DAY, 0);
        dateStart.set(Calendar.MINUTE, 0);
        dateStart.set(Calendar.SECOND, 0);
        return dateStart.getTime();
    }

    /**
     * 获取每天的结束时间 23:59:59:999
     *
     * @param date 时间
     * @return 本日结束时间
     */
    public static Date getDayEndTime(Date date) {
        Calendar dateEnd = Calendar.getInstance();
        dateEnd.setTime(date);
        dateEnd.set(Calendar.HOUR_OF_DAY, 23);
        dateEnd.set(Calendar.MINUTE, 59);
        dateEnd.set(Calendar.SECOND, 59);
        return dateEnd.getTime();
    }

    /**
     * 获取所在周的开始时间 00:00:00:00
     *
     * @param date 时间
     * @return 本周开始时间
     */
    public static Date getWeeklyStartTime(Date date) {
        int mondayPlus = getMondayPlus(date);
        GregorianCalendar currentDate = new GregorianCalendar();
        currentDate.add(Calendar.DATE, mondayPlus);
        currentDate.set(Calendar.HOUR_OF_DAY, 0);
        currentDate.set(Calendar.MINUTE, 0);
        currentDate.set(Calendar.SECOND, 0);
        currentDate.set(Calendar.MILLISECOND, 0);
        return currentDate.getTime();
    }

    /**
     * 获取获取所在周的结束时间 23:59:59:999
     *
     * @param date 当前时间
     * @return 本周结束时间
     */
    public static Date getWeeklyEndTime(Date date) {
        int mondayPlus = getMondayPlus(date);
        GregorianCalendar currentDate = new GregorianCalendar();
        currentDate.add(Calendar.DATE, mondayPlus + 6);
        currentDate.set(Calendar.HOUR_OF_DAY, 23);
        currentDate.set(Calendar.MINUTE, 59);
        currentDate.set(Calendar.SECOND, 59);
        currentDate.set(Calendar.MILLISECOND, 999);
        return currentDate.getTime();
    }

    /**
     * 获取本季度开始时间戳
     *
     * @return 本季度开始时间
     */
    public static Date getQuarterStartTime() {
        LocalDate now = LocalDate.now();
        int currentMonth = now.getMonthValue();
        Month quarterStartMonth = Month.of((currentMonth - 1) / 3 * 3 + 1);
        LocalDate quarterStartDate = LocalDate.of(now.getYear(), quarterStartMonth, 1);
        long milli = quarterStartDate.atStartOfDay().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(milli);
        // 设置为1号,当前日期既为本月第一天
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * 获取本季度结束时间戳
     *
     * @return 本季度结束时间
     */
    public static Date getQuarterEndTime() {
        LocalDate now = LocalDate.now();
        int currentMonth = now.getMonthValue();
        Month quarterStartMonth = Month.of((currentMonth - 1) / 3 * 3 + 1);
        LocalDate quarterStartDate = LocalDate.of(now.getYear(), quarterStartMonth, 1);
        LocalDate quarterEndDate = quarterStartDate.plusMonths(2).withDayOfMonth(quarterStartDate.plusMonths(2).lengthOfMonth());
        long milli = quarterEndDate.atStartOfDay().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(milli);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar.getTime();
    }

    /**
     * 获取年份开始时间戳
     *
     * @param date 时间
     * @return 当年开始时间
     */
    public static Date getYearStartTime(Date date) {
        // 获取当前日期
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        // 设置为1号,当前日期既为本月第一天
        calendar.set(Calendar.MONTH, 0);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * 获取年份结束时间戳
     *
     * @param date 时间
     * @return 当年结束时间
     */
    public static Date getYearEndTime(Date date) {
        // 获取当前日期
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        // 设置为1号,当前日期既为本月第一天
        calendar.set(Calendar.MONTH, 11);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar.getTime();
    }

    /**
     * 获取月份开始时间戳
     *
     * @param date 时间
     * @return 当月开始时间
     */
    public static Date getMonthStartTime(Date date) {
        // 获取当前日期
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.YEAR, 0);
        calendar.add(Calendar.MONTH, 0);
        // 设置为1号,当前日期既为本月第一天
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * 获取月份的结束时间戳
     *
     * @param date 时间
     * @return 当月结束时间
     */
    public static Date getMonthEndTime(Date date) {
        // 获取当前日期
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        // 获取当前月最后一天
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar.getTime();
    }

    /**
     * date 是否在startDate和endDate的区间内
     * date 如果为null 则返回false
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @param date      被判断的时间
     * @return 是否在区间内
     */
    public static Boolean isBetween(Date startDate, Date endDate, Date date) {
        if (date == null) {
            return Boolean.FALSE;
        }
        return startDate.before(date) && endDate.after(date);
    }

    /**
     * 格式化日期
     *
     * @param date    日期
     * @param pattern 格式
     * @return String
     */
    public static String format(Date date, String pattern) {
        if (date == null) {
            return null;
        }
        if (pattern == null) {
            return formatDate(date);
        }
        return new SimpleDateFormat(pattern).format(date);
    }

    /**
     * 格式化日期（yyyy-MM-dd HH:mm:ss）
     */
    public static String formatDate(Date date) {
        return format(date, DATE_FORMAT);
    }

    /**
     * 格式化日期（yyyy-MM-dd）
     */
    public static String formatSimpleDate(Date date) {
        return format(date, SIMPLE_FORMAT);
    }

    /**
     * 格式化日期（MM-dd）
     */
    public static String formatMonthDate(Date date) {
        return format(date, DATE_MOUTH_FORMAT);
    }

    /**
     * 格式化日期（hh）
     */
    public static String formatHourDate(Date date) {
        return format(date, DATE_HOURS_FORMAT);
    }

    /**
     * 格式化日期（MMdd）
     */
    public static String getDateStr() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat(DATE_STR_FORMAT, Locale.ENGLISH);
        return sdf.format(date);
    }

    /**
     * 将时间单位为毫秒的值转换为"时:分:秒"的格式
     *
     * @param milliseconds 毫秒
     * @return "时:分:秒"
     */
    public static String formatMillisecond(Long milliseconds) {
        int seconds = (int) (milliseconds / 1000) % 60;
        int minutes = (int) ((milliseconds / (1000 * 60)) % 60);
        int hours = (int) ((milliseconds / (1000 * 60 * 60)) % 24);
        return String.format("%02d:%02d:%02d", hours, minutes, seconds);
    }

    /**
     * 根据时间段获取日期集合-天
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return 时间集合
     */
    public static List<String> getDataListByDay(Date startDate, Date endDate) {
        startDate = DateUtils.getDayStartTime(startDate);
        endDate = DateUtils.getDayStartTime(endDate);
        List<String> dataList = Lists.newArrayList();
        Calendar startTime = Calendar.getInstance();
        Calendar endTime = Calendar.getInstance();
        try {
            //将开始日期设置给calendar
            startTime.setTime(startDate);
            //日期减1，包含开始日期
            startTime.add(Calendar.DATE, -1);
            //将结束日期设置给calendar
            endTime.setTime(endDate);
            while (startTime.before(endTime)) {
                startTime.add(Calendar.DAY_OF_MONTH, 1);
                dataList.add(DateUtil.format(startTime.getTime(), DATE_MOUTH_FORMAT));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dataList;
    }

    /**
     * 获取两个时间范围中的小时集合
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return
     */
    public static List<String> getHours(Date startDate, Date endDate) {
        List<String> hours = new ArrayList<>();
        Calendar start = Calendar.getInstance();
        start.setTime(startDate);
        Calendar end = Calendar.getInstance();
        end.setTime(endDate);
        while (start.before(end)) {
            int hour = start.get(Calendar.HOUR_OF_DAY);
            hours.add(String.valueOf(hour));
            start.add(Calendar.HOUR_OF_DAY, 1);
        }
        return hours;
    }
}
